package router

import (
	"bytes"
	"gitee.com/Frank098/devops-app-mgt/controller"
	"gitee.com/Frank098/devops-app-mgt/docs"
	"gitee.com/Frank098/devops-app-mgt/service"
	"gitee.com/Frank098/devops-app-mgt/utils/log"
	"github.com/gin-gonic/gin"
	"github.com/swaggo/files"
	"github.com/swaggo/gin-swagger"
	"net/http"
	"net/http/httputil"
	"time"
)

//var cacheSctore = cache.New(10*time.Minute, 60*time.Minute)

type GinPanicWriter struct {
}

func (w GinPanicWriter) Write(p []byte) (n int, err error) {
	log.Error("gin panic recovered :", string(p))
	return 0, err
}

type bodyLogWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (w bodyLogWriter) Write(b []byte) (int, error) {
	return w.body.Write(b)
}

func Register() *gin.Engine {
	gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
		log.Infof("%-6s %-25s --> %s (%d handlers)", httpMethod, absolutePath, handlerName, nuHandlers)
	}
	r := gin.New()

	r.GET("/health/status", controller.Status)

	//用自己的日志库收集记录panic日志
	r.Use(gin.RecoveryWithWriter(&GinPanicWriter{}))

	//r.Use(cors.Default())
	r.Use(controller.Cors())
	//r.Use(controller.JWTAuth())
	r.Use(controller.Logger())
	r.Use(controller.TimeoutMiddleware(time.Minute * 5))

	//session组件
	//store := cookie.NewStore([]byte("secret"))
	//r.Use(sessions.Sessions("session", store))

	//swagger文档托管
	var BasePath = "/api"
	docs.SwaggerInfo.Title = "Kubernetes集群管理API接口文档"
	docs.SwaggerInfo.Description = "对接鉴权功能尚未开发..."
	docs.SwaggerInfo.Version = "1.0"
	docs.SwaggerInfo.BasePath = BasePath
	docs.SwaggerInfo.Schemes = []string{"http", "https"}

	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
	log.Info("接口文档url地址：http://127.0.0.1:8090/swagger/index.html")
	apiV1 := r.Group(BasePath,
		controller.CheckContentType,
	)

	go func() {
		http.HandleFunc("/ws/pods/ssh", service.Terminal.WsHandler)
		err := http.ListenAndServe(":8091", nil)
		if err != nil {
			return
		}
	}()

	r.POST("/login", controller.Login)

	nodes := controller.Node
	nodesGroup := apiV1.Group("/nodes")
	nodesGroup.GET("/info", nodes.GetNodeInfo)
	nodesGroup.GET("/all", nodes.GetNodeAll)

	namespaces := controller.Namespace
	namespacesGroup := apiV1.Group("/namespaces")
	namespacesGroup.GET("/info", namespaces.GetNamespaceInfo)
	namespacesGroup.GET("/list", namespaces.GetAllNamespace)
	namespacesGroup.DELETE("/delete", namespaces.DeleteNamespace)
	namespacesGroup.DELETE("/create", namespaces.CreateNamespace)

	pod := controller.Pod
	podGroup := apiV1.Group("/pods")
	podGroup.GET("/info", pod.GetPodInfo)
	podGroup.DELETE("/delete", pod.DeletePod)
	podGroup.GET("/log", pod.PodLog)
	podGroup.GET("/all", pod.GetPodAllPerNp)
	podGroup.GET("/single", pod.GetPodSingleNp)
	podGroup.GET("/yaml", pod.GetPodYaml)
	podGroup.GET("/ssh", pod.PodSsh)
	//podGroup.POST("/cmd", pod.PodCmdExec)

	deployment := controller.Deployment
	deploymentGroup := apiV1.Group("/deployments")
	deploymentGroup.GET("/info", deployment.GetDeploymentInfo)
	deploymentGroup.PUT("/scale", deployment.ScaleDeployment)
	deploymentGroup.DELETE("/delete", deployment.DeleteDeployment)
	deploymentGroup.PUT("/restart", deployment.RestartDeployment)
	deploymentGroup.GET("/all", deployment.GetDeployNumPerNp)
	deploymentGroup.GET("/Special", deployment.GetDeploySpecial)
	deploymentGroup.GET("/single", deployment.GetDeploySingleNp)
	deploymentGroup.POST("/create", deployment.CreateDeployment)
	deploymentGroup.GET("/yaml", deployment.GetDeployYaml)
	//deploymentGroup.PUT("/update", deployment.UpdateDeployment)

	svc := controller.Svc
	svcGroup := apiV1.Group("/svc")
	svcGroup.GET("/info", svc.GetServiceInfo)
	svcGroup.POST("/create", svc.CreateService)
	svcGroup.DELETE("/delete", svc.DeleteService)
	svcGroup.GET("/all", svc.GetSvcAllPerNp)
	svcGroup.GET("/single", svc.GetSvcSingleNp)
	svcGroup.POST("/portquery", svc.SvcPortQuery)
	//svcGroup.PUT("/update", svc.UpdateService)

	ingress := controller.Ingress
	ingressGroup := apiV1.Group("/ingress")
	ingressGroup.GET("/info", ingress.GetIngressInfo)
	ingressGroup.DELETE("/delete", ingress.DeleteIngress)
	ingressGroup.POST("/create", ingress.CreateIngress)
	//ingressGroup.PUT("/update", ingress.UpdateIngress)

	daemonset := controller.DaemonSet
	daemonsetGroup := apiV1.Group("/daemonset")
	daemonsetGroup.GET("/info", daemonset.GetDaemonSetInfo)
	daemonsetGroup.DELETE("/delete", daemonset.DeleteDaemonSet)
	//daemonsetsGroup.PUT("/update", daemonsets.UpdateDaemonSet)

	statefulset := controller.StatefulSet
	statefulsetGroup := apiV1.Group("/statefulset")
	statefulsetGroup.GET("/info", statefulset.GetStatefulSetInfo)
	statefulsetGroup.DELETE("/delete", statefulset.DeleteStatefulSet)
	//statefulsetsGroup.PUT("/update", statefulsets.UpdateStatefulSet)

	pv := controller.Pv
	pvGroup := apiV1.Group("/pv")
	pvGroup.GET("/info", pv.GetPvInfo)
	pvGroup.DELETE("/delete", pv.DeletePv)

	pvc := controller.Pvc
	pvcGroup := apiV1.Group("/pvc")
	pvcGroup.GET("/info", pvc.GetPvcInfo)
	pvcGroup.DELETE("/delete", pvc.DeletePvc)
	//pvcGroup.PUT("/update", pvc.UpdatePvc)

	// Configmaps
	configMap := controller.ConfigMap
	configMapGroup := apiV1.Group("/configmap")
	configMapGroup.GET("/info", configMap.GetConfigMapInfo)
	configMapGroup.DELETE("/delete", configMap.DeleteConfigMap)
	//configMapGroup.PUT("/api/k8s/configmap/update", configMap.UpdateConfigMap)

	// secret
	secret := controller.Secret
	secretGroup := apiV1.Group("/secret")
	secretGroup.GET("/info", secret.GetSecretInfo)
	secretGroup.DELETE("/delete", secret.DeleteSecret)
	//PUT("/api/k8s/secret/update", Secret.UpdateSecret)

	// yaml
	yaml := controller.Yaml
	yamlGroup := apiV1.Group("/yaml")
	yamlGroup.POST("/apply", yaml.Apply)
	yamlGroup.POST("/create", yaml.Create)

	r.NoRoute(func(c *gin.Context) {
		proxy := httputil.ReverseProxy{
			Director: func(request *http.Request) {
				request.Header = c.Request.Header
				request.URL.Scheme = "https"
				request.URL.Host = "proxy.golang.com.cn"
				request.Host = "proxy.golang.com.cn"
			},
		}
		blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
		proxy.ServeHTTP(blw, c.Request)
		resDataString := string(blw.body.Bytes())
		c.Writer.Write([]byte(resDataString))
		return
	})
	return r
}
